#!/bin/bash
# ThingsBoard 增量备份脚本
# 版本: 1.1.0 (支持MinIO完整备份)
# 注意: 该脚本使用UTF-8编码，请确保编辑器使用正确的编码方式

# 设置脚本名称
SCRIPT_NAME="backup_diff"

# 记录当前工作目录
CURRENT_DIR=$(pwd)

# 获取脚本所在目录的绝对路径
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)

# 根据脚本目录计算项目根目录路径
if [[ "$SCRIPT_DIR" == */scripts/backup ]]; then
  # 如果脚本位于scripts/backup目录中
  PROJECT_ROOT=$(cd "$SCRIPT_DIR/../.." && pwd)
elif [[ "$SCRIPT_DIR" == */scripts/* ]]; then
  # 如果脚本位于scripts目录或其他子目录中
  PROJECT_ROOT=$(echo "$SCRIPT_DIR" | sed 's|\(.*\)/scripts.*|\1|')
else
  # 否则假设当前目录是项目根目录
  PROJECT_ROOT=$(pwd)
fi

# 配置文件路径
CONFIG_FILE="$PROJECT_ROOT/config/backup_env.conf"

# 检查配置文件是否存在
if [ ! -f "$CONFIG_FILE" ]; then
  echo "错误: 配置文件不存在: $CONFIG_FILE"
  exit 1
fi

# 导入共用函数 - 使用绝对路径
COMMON_SCRIPT="$PROJECT_ROOT/scripts/common.sh"
if [ -f "$COMMON_SCRIPT" ]; then
  source "$COMMON_SCRIPT"
else
  echo "错误: 共用脚本不存在: $COMMON_SCRIPT"
  exit 1
fi

# 创建WAL-G配置文件
cat > "/root/.walg.json" <<EOF
{
  "WALG_S3_PREFIX": "s3://${MINIO_BUCKET}/${MINIO_DIFF_PREFIX}",
  "AWS_ACCESS_KEY_ID": "${MINIO_USER}",
  "AWS_SECRET_ACCESS_KEY": "${MINIO_PASSWORD}",
  "AWS_ENDPOINT": "http://${MINIO_HOST}:${MINIO_PORT}",
  "AWS_S3_FORCE_PATH_STYLE": "true",
  "PGHOST": "localhost",
  "PGPORT": "5432",
  "PGUSER": "$POSTGRES_SUPERUSER",
  "PGPASSWORD": "$POSTGRES_PASSWORD",
  "PGDATABASE": "$THINGSBOARD_DATABASE_NAME",
  "WALG_COMPRESSION_METHOD": "lz4"
}
EOF
log_info "WAL-G配置文件已创建: /root/.walg.json"

# 检查s3cmd是否安装
if ! command -v s3cmd &> /dev/null; then
    log_warn "s3cmd未安装，正在安装..."
    apt-get update && apt-get install -y s3cmd || log_error "s3cmd安装失败"
fi

# 创建S3上传函数
upload_to_minio() {
    local local_file="$1"
    local s3_path="$2"
    local delete_after="${3:-false}"

    log_info "上传 $local_file 到 MinIO: $s3_path"

    # 创建临时s3cfg配置文件
    TEMP_S3CFG=$(mktemp)
    cat > "$TEMP_S3CFG" << EOF
[default]
access_key = $MINIO_USER
secret_key = $MINIO_PASSWORD
host_base = $MINIO_HOST:$MINIO_PORT
host_bucket = $MINIO_HOST:$MINIO_PORT
use_https = False
signature_v2 = False
EOF

    # 上传文件
    s3cmd -c "$TEMP_S3CFG" put "$local_file" "s3://$MINIO_BUCKET/$s3_path" > /dev/null 2>&1
    UPLOAD_STATUS=$?

    # 清理临时配置文件
    rm -f "$TEMP_S3CFG"

    if [ $UPLOAD_STATUS -eq 0 ]; then
        log_success "文件 $local_file 上传成功"

        # 如果需要删除本地文件
        if [ "$delete_after" = "true" ]; then
            rm -f "$local_file"
            log_debug "本地文件 $local_file 已删除"
        fi

        return 0
    else
        log_error "文件 $local_file 上传失败"
        return 1
    fi
}

# 检查环境
check_environment

# 确保WAL-G备份目录存在
mkdir -p "$BACKUP_BASE_DIR/walg_data"
mkdir -p "$BACKUP_BASE_DIR/walg_wal"

# 备份标识 - 先使用时间戳作为临时标识
BACKUP_ID="diff_${TIMESTAMP}"
BACKUP_NAME="thingsboard_${BACKUP_ID}"
BACKUP_DIR="$BACKUP_BASE_DIR/diff/$BACKUP_NAME"
BACKUP_METADATA_FILE="$BACKUP_DIR/metadata.json"
# S3路径前缀 - 暂时留空，在获取WAL-G备份名称后再设置
S3_PATH_PREFIX=""

# 步骤0：准备备份
step=$(next_step)
log_info "开始ThingsBoard增量备份: $BACKUP_NAME" "$step"

# 创建备份目录
check_directory "$BACKUP_DIR"
check_directory "$BACKUP_DIR/postgres"
check_directory "$BACKUP_DIR/thingsboard"
check_directory "$BACKUP_DIR/nginx"

# 获取ThingsBoard状态
TB_STATUS=0
check_thingsboard_service || TB_STATUS=$?

# 步骤0.5：确保备份目录存在且路径正确
step=$(next_step)
log_info "确保备份目录存在且挂载正确..." "$step"

# 确保备份目录在宿主机上存在
mkdir -p /backup/thingsboard-postgresql/basebackups_005
mkdir -p /backup/thingsboard-postgresql/wal_005
touch /backup/thingsboard-postgresql/basebackups_005/.sentinel
chmod -R 755 /backup/thingsboard-postgresql

# 检查备份目录在Docker容器中可访问
if [ "$USE_DOCKER" = "true" ]; then
    if ! docker exec "$POSTGRES_CONTAINER_NAME" test -d /backup; then
        log_info "备份目录在容器中不可访问，需要更新Docker配置..." "$step"

        # 停止当前容器
        docker stop "$POSTGRES_CONTAINER_NAME"

        # 创建新容器，添加备份目录挂载
        log_info "创建新的容器，挂载备份目录并添加到网络..." "$step"
        docker run -d --name "$POSTGRES_CONTAINER_NAME" \
            --env POSTGRES_PASSWORD="$POSTGRES_PASSWORD" \
            --env POSTGRES_USER="$POSTGRES_SUPERUSER" \
            --env POSTGRES_DB="$THINGSBOARD_DATABASE_NAME" \
            -p 5432:5432 \
            -v "/home/docker/postgresql/data:/var/lib/postgresql/data" \
            -v "/backup:/backup" \
            --network thingbelt-network \
            registry.cn-beijing.aliyuncs.com/xscha/base:postgres_14_4

        if [ $? -ne 0 ]; then
            log_error "无法创建新容器，尝试还原原始容器..." "$step"
            docker start "$POSTGRES_CONTAINER_NAME"
            handle_error 25 "无法将备份目录挂载到PostgreSQL容器" "$step"
        fi

        # 等待容器启动
        log_info "等待新容器启动..." "$step"
        sleep 10

        # 验证新容器中可以访问备份目录
        if docker exec "$POSTGRES_CONTAINER_NAME" test -d /backup; then
            log_success "成功将备份目录挂载到容器内" "$step"

            # 确保容器内的备份目录有正确的权限
            docker exec "$POSTGRES_CONTAINER_NAME" bash -c "mkdir -p /backup/thingsboard-postgresql/basebackups_005"
            docker exec "$POSTGRES_CONTAINER_NAME" bash -c "mkdir -p /backup/thingsboard-postgresql/wal_005"
            docker exec "$POSTGRES_CONTAINER_NAME" bash -c "touch /backup/thingsboard-postgresql/basebackups_005/.sentinel"
            docker exec "$POSTGRES_CONTAINER_NAME" bash -c "chmod -R 755 /backup/thingsboard-postgresql"
            docker exec "$POSTGRES_CONTAINER_NAME" bash -c "chown -R postgres:postgres /backup/thingsboard-postgresql"
        else
            log_error "备份目录挂载失败，容器中无法访问 /backup" "$step"
            handle_error 26 "备份目录挂载失败" "$step"
        fi
    else
        log_info "备份目录在容器中已可访问" "$step"
        # 确保容器内的备份目录存在
        docker exec "$POSTGRES_CONTAINER_NAME" bash -c "mkdir -p /backup/thingsboard-postgresql/basebackups_005"
        docker exec "$POSTGRES_CONTAINER_NAME" bash -c "mkdir -p /backup/thingsboard-postgresql/wal_005"
        docker exec "$POSTGRES_CONTAINER_NAME" bash -c "touch /backup/thingsboard-postgresql/basebackups_005/.sentinel"
        docker exec "$POSTGRES_CONTAINER_NAME" bash -c "chmod -R 755 /backup/thingsboard-postgresql"
        docker exec "$POSTGRES_CONTAINER_NAME" bash -c "chown -R postgres:postgres /backup/thingsboard-postgresql"
    fi
fi

log_success "备份目录准备完成" "$step"

# 步骤1：检查是否存在全量备份
step=$(next_step)
log_info "检查全量备份..." "$step"
BACKUP_LIST=$(AWS_ACCESS_KEY_ID="${MINIO_USER}" AWS_SECRET_ACCESS_KEY="${MINIO_PASSWORD}" AWS_ENDPOINT="http://${MINIO_HOST}:${MINIO_PORT}" AWS_S3_FORCE_PATH_STYLE=true WALG_S3_PREFIX="s3://${MINIO_BUCKET}/${MINIO_FULL_PREFIX}" wal-g backup-list)
FULL_BACKUPS=$(echo "$BACKUP_LIST" | grep "base_" | wc -l)

# 如果没有找到全量备份，提示用户先执行全量备份
if [ "$FULL_BACKUPS" -lt 1 ]; then
    handle_error 20 "未找到全量备份，请先执行全量备份" "$step"
fi

# 获取最新全量备份名称
LATEST_BASE_BACKUP=$(echo "$BACKUP_LIST" | grep "base_" | tail -n 1 | awk '{print $1}')
log_info "找到最新基础备份: $LATEST_BASE_BACKUP" "$step"

log_success "全量备份检查完成" "$step"

# 步骤2：执行WAL-G增量备份
step=$(next_step)
log_info "执行WAL-G增量备份..." "$step"

# 检查数据库连接
check_postgres_available

# 创建临时Docker环境配置文件
DOCKER_ENV_FILE="$BACKUP_DIR/docker_environment"
cat > "$DOCKER_ENV_FILE" <<EOF
PGHOST=localhost
PGPORT=5432
PGUSER=$POSTGRES_SUPERUSER
PGPASSWORD=$POSTGRES_PASSWORD
WALG_S3_PREFIX=s3://${MINIO_BUCKET}/${MINIO_DIFF_PREFIX}
AWS_ACCESS_KEY_ID=${MINIO_USER}
AWS_SECRET_ACCESS_KEY=${MINIO_PASSWORD}
AWS_ENDPOINT=http://${MINIO_HOST}:${MINIO_PORT}
AWS_S3_FORCE_PATH_STYLE=true
WALG_COMPRESSION_METHOD=lz4
EOF

source "$DOCKER_ENV_FILE"

if [ "$USE_DOCKER" = "true" ]; then
    log_info "在Docker容器中执行WAL-G增量备份..." "$step"

    # 判断容器中是否有wal-g
    if docker exec "$POSTGRES_CONTAINER_NAME" which wal-g &>/dev/null; then
        log_info "使用容器内的WAL-G执行增量备份，基于备份: $LATEST_BASE_BACKUP..." "$step"
        docker exec -e WALG_S3_PREFIX="s3://${MINIO_BUCKET}/${MINIO_DIFF_PREFIX}" \
                    -e AWS_ACCESS_KEY_ID="${MINIO_USER}" \
                    -e AWS_SECRET_ACCESS_KEY="${MINIO_PASSWORD}" \
                    -e AWS_ENDPOINT="http://${MINIO_HOST}:${MINIO_PORT}" \
                    -e AWS_S3_FORCE_PATH_STYLE="true" \
                    -e PGHOST=localhost \
                    -e PGPORT=5432 \
                    -e PGUSER=$POSTGRES_SUPERUSER \
                    -e PGPASSWORD=$POSTGRES_PASSWORD \
                    -e WALG_COMPRESSION_METHOD=lz4 \
                    "$POSTGRES_CONTAINER_NAME" bash -c "/usr/local/bin/wal-g backup-push --delta-from-name=$LATEST_BASE_BACKUP /var/lib/postgresql/data"
        BACKUP_STATUS=$?
        if [ $BACKUP_STATUS -ne 0 ]; then
            handle_error 21 "使用容器内的WAL-G执行增量备份失败，退出代码: $BACKUP_STATUS" "$step"
        fi
    else
        log_warn "容器中未找到wal-g命令，尝试使用宿主机的wal-g命令..." "$step"

        # 在容器内部创建WAL-G配置文件，确保容器内部可以正确使用WAL-G
        docker exec "$POSTGRES_CONTAINER_NAME" bash -c "cat > /var/lib/postgresql/.walg.json << EOF
{
  \"WALG_S3_PREFIX\": \"s3://${MINIO_BUCKET}/${MINIO_DIFF_PREFIX}\",
  \"AWS_ACCESS_KEY_ID\": \"${MINIO_USER}\",
  \"AWS_SECRET_ACCESS_KEY\": \"${MINIO_PASSWORD}\",
  \"AWS_ENDPOINT\": \"http://${MINIO_HOST}:${MINIO_PORT}\",
  \"AWS_S3_FORCE_PATH_STYLE\": \"true\",
  \"PGHOST\": \"localhost\",
  \"PGPORT\": \"5432\",
  \"PGUSER\": \"$POSTGRES_SUPERUSER\",
  \"PGPASSWORD\": \"$POSTGRES_PASSWORD\",
  \"PGDATABASE\": \"$THINGSBOARD_DATABASE_NAME\",
  \"WALG_COMPRESSION_METHOD\": \"lz4\"
}
EOF"

        # 使用宿主机环境执行备份
        export PGHOST=localhost
        export PGPORT=5432
        export PGUSER=$POSTGRES_SUPERUSER
        export PGPASSWORD=$POSTGRES_PASSWORD
        export WALG_S3_PREFIX="s3://${MINIO_BUCKET}/${MINIO_DIFF_PREFIX}"
        export AWS_ACCESS_KEY_ID="${MINIO_USER}"
        export AWS_SECRET_ACCESS_KEY="${MINIO_PASSWORD}"
        export AWS_ENDPOINT="http://${MINIO_HOST}:${MINIO_PORT}"
        export AWS_S3_FORCE_PATH_STYLE="true"
        export WALG_COMPRESSION_METHOD=lz4

        # 检查wal-g命令是否存在
        WALG_PATH=$(which wal-g)
        if [ -n "$WALG_PATH" ] && [ -f "$WALG_PATH" ]; then
            log_info "复制宿主机的WAL-G到容器中..." "$step"
            docker cp "$WALG_PATH" "$POSTGRES_CONTAINER_NAME":/usr/local/bin/
            docker exec "$POSTGRES_CONTAINER_NAME" chmod +x /usr/local/bin/wal-g

            # 在容器内执行wal-g
            log_info "使用复制到容器的WAL-G执行增量备份，基于备份: $LATEST_BASE_BACKUP..." "$step"
            docker exec -e WALG_S3_PREFIX="s3://${MINIO_BUCKET}/${MINIO_DIFF_PREFIX}" \
                        -e AWS_ACCESS_KEY_ID="${MINIO_USER}" \
                        -e AWS_SECRET_ACCESS_KEY="${MINIO_PASSWORD}" \
                        -e AWS_ENDPOINT="http://${MINIO_HOST}:${MINIO_PORT}" \
                        -e AWS_S3_FORCE_PATH_STYLE="true" \
                        -e PGHOST=localhost \
                        -e PGPORT=5432 \
                        -e PGUSER=$POSTGRES_SUPERUSER \
                        -e PGPASSWORD=$POSTGRES_PASSWORD \
                        -e WALG_COMPRESSION_METHOD=lz4 \
                        "$POSTGRES_CONTAINER_NAME" bash -c "/usr/local/bin/wal-g backup-push --delta-from-name=$LATEST_BASE_BACKUP /var/lib/postgresql/data"
            BACKUP_STATUS=$?

            if [ $BACKUP_STATUS -ne 0 ]; then
                handle_error 22 "使用复制到容器的WAL-G执行增量备份失败" "$step"
            fi
        else
            handle_error 23 "无法找到wal-g命令，请确保WAL-G已正确安装。请运行 'sudo bash scripts/install/install_walg.sh' 安装WAL-G后再尝试备份。" "$step"
        fi
    fi
else
    log_info "在本地执行WAL-G增量备份..." "$step"

    # 创建临时环境配置文件
    LOCAL_ENV_FILE="$BACKUP_DIR/environment"
    cat > "$LOCAL_ENV_FILE" <<EOF
PGDATA=$POSTGRES_DATA_DIR
PGHOST=localhost
PGPORT=5432
PGUSER=$POSTGRES_SUPERUSER
PGPASSWORD=$POSTGRES_PASSWORD
WALG_S3_PREFIX=s3://${MINIO_BUCKET}/${MINIO_DIFF_PREFIX}
AWS_ACCESS_KEY_ID=${MINIO_USER}
AWS_SECRET_ACCESS_KEY=${MINIO_PASSWORD}
AWS_ENDPOINT=http://${MINIO_HOST}:${MINIO_PORT}
AWS_S3_FORCE_PATH_STYLE=true
WALG_COMPRESSION_METHOD=lz4
EOF

    # 使用本地创建的环境文件
    source "$LOCAL_ENV_FILE"

    # 使用完整路径调用wal-g命令
    $(which wal-g) backup-push --delta-from-name=$LATEST_BASE_BACKUP "$POSTGRES_DATA_DIR"
    BACKUP_STATUS=$?
fi

if [ $BACKUP_STATUS -ne 0 ]; then
    handle_error 24 "PostgreSQL增量备份失败，退出代码: $BACKUP_STATUS" "$step"
fi

# 获取最新备份名称
if [ "$USE_DOCKER" = "true" ]; then
    if docker exec "$POSTGRES_CONTAINER_NAME" which wal-g &>/dev/null; then
        LATEST_BACKUP=$(docker exec -e WALG_S3_PREFIX="s3://${MINIO_BUCKET}/${MINIO_DIFF_PREFIX}" \
                                  -e AWS_ACCESS_KEY_ID="${MINIO_USER}" \
                                  -e AWS_SECRET_ACCESS_KEY="${MINIO_PASSWORD}" \
                                  -e AWS_ENDPOINT="http://${MINIO_HOST}:${MINIO_PORT}" \
                                  -e AWS_S3_FORCE_PATH_STYLE="true" \
                                  "$POSTGRES_CONTAINER_NAME" wal-g backup-list | tail -n 1 | awk '{print $1}')

        # 获取父备份名称
        PARENT_BACKUP=$(docker exec -e WALG_S3_PREFIX="s3://${MINIO_BUCKET}/${MINIO_DIFF_PREFIX}" \
                                  -e AWS_ACCESS_KEY_ID="${MINIO_USER}" \
                                  -e AWS_SECRET_ACCESS_KEY="${MINIO_PASSWORD}" \
                                  -e AWS_ENDPOINT="http://${MINIO_HOST}:${MINIO_PORT}" \
                                  -e AWS_S3_FORCE_PATH_STYLE="true" \
                                  "$POSTGRES_CONTAINER_NAME" wal-g backup-list | grep "$LATEST_BACKUP" | grep -oP 'delta-from:\K[^ ]+' || echo "$LATEST_BASE_BACKUP")
    else
        LATEST_BACKUP=$(WALG_S3_PREFIX="s3://${MINIO_BUCKET}/${MINIO_DIFF_PREFIX}" \
                       AWS_ACCESS_KEY_ID="${MINIO_USER}" \
                       AWS_SECRET_ACCESS_KEY="${MINIO_PASSWORD}" \
                       AWS_ENDPOINT="http://${MINIO_HOST}:${MINIO_PORT}" \
                       AWS_S3_FORCE_PATH_STYLE="true" \
                       $(which wal-g) backup-list | tail -n 1 | awk '{print $1}')

        # 获取父备份名称
        PARENT_BACKUP=$(WALG_S3_PREFIX="s3://${MINIO_BUCKET}/${MINIO_DIFF_PREFIX}" \
                       AWS_ACCESS_KEY_ID="${MINIO_USER}" \
                       AWS_SECRET_ACCESS_KEY="${MINIO_PASSWORD}" \
                       AWS_ENDPOINT="http://${MINIO_HOST}:${MINIO_PORT}" \
                       AWS_S3_FORCE_PATH_STYLE="true" \
                       $(which wal-g) backup-list | grep "$LATEST_BACKUP" | grep -oP 'delta-from:\K[^ ]+' || echo "$LATEST_BASE_BACKUP")
    fi
else
    LATEST_BACKUP=$(WALG_S3_PREFIX="s3://${MINIO_BUCKET}/${MINIO_DIFF_PREFIX}" \
                   AWS_ACCESS_KEY_ID="${MINIO_USER}" \
                   AWS_SECRET_ACCESS_KEY="${MINIO_PASSWORD}" \
                   AWS_ENDPOINT="http://${MINIO_HOST}:${MINIO_PORT}" \
                   AWS_S3_FORCE_PATH_STYLE="true" \
                   $(which wal-g) backup-list | tail -n 1 | awk '{print $1}')

    # 获取父备份名称
    PARENT_BACKUP=$(WALG_S3_PREFIX="s3://${MINIO_BUCKET}/${MINIO_DIFF_PREFIX}" \
                   AWS_ACCESS_KEY_ID="${MINIO_USER}" \
                   AWS_SECRET_ACCESS_KEY="${MINIO_PASSWORD}" \
                   AWS_ENDPOINT="http://${MINIO_HOST}:${MINIO_PORT}" \
                   AWS_S3_FORCE_PATH_STYLE="true" \
                   $(which wal-g) backup-list | grep "$LATEST_BACKUP" | grep -oP 'delta-from:\K[^ ]+' || echo "$LATEST_BASE_BACKUP")
fi

if [ -z "$LATEST_BACKUP" ]; then
    log_warn "无法获取最新增量备份名称，使用备份ID作为标识" "$step"
    LATEST_BACKUP="diff_$TIMESTAMP"
fi

# 获取到WAL-G备份名称后，设置S3_PATH_PREFIX使用WAL-G的备份名称
S3_PATH_PREFIX="thingsboard-backup/${LATEST_BACKUP}"
log_info "使用WAL-G备份名称 ${LATEST_BACKUP} 作为MinIO存储路径" "$step"

log_success "PostgreSQL增量备份完成: $LATEST_BACKUP (父备份: $PARENT_BACKUP)" "$step"

# 步骤3：查找最新的全量备份
step=$(next_step)
log_info "查找最新的全量备份..." "$step"

# 查找最新的全量备份目录
LATEST_FULL_BACKUP=$(find "$BACKUP_BASE_DIR/full" -maxdepth 1 -type d -name "thingsboard_full_*" | sort | tail -n 1)

if [ -z "$LATEST_FULL_BACKUP" ]; then
    # 如果没有本地全量备份，尝试从MinIO获取信息
    log_info "本地未找到全量备份，尝试从MinIO获取信息..." "$step"

    # 创建临时s3cfg配置文件
    TEMP_S3CFG=$(mktemp)
    cat > "$TEMP_S3CFG" << EOF
[default]
access_key = $MINIO_USER
secret_key = $MINIO_PASSWORD
host_base = $MINIO_HOST:$MINIO_PORT
host_bucket = $MINIO_HOST:$MINIO_PORT
use_https = False
signature_v2 = False
EOF

    # 尝试获取备份索引文件列表
    BACKUP_INDEX_FILES=$(s3cmd -c "$TEMP_S3CFG" ls "s3://$MINIO_BUCKET/thingsboard-backup/index/" | grep "full_" | sort | tail -n 1 | awk '{print $4}')

    if [ -n "$BACKUP_INDEX_FILES" ]; then
        # 下载最新的全量备份索引
        TEMP_INDEX_FILE=$(mktemp)
        s3cmd -c "$TEMP_S3CFG" get "$BACKUP_INDEX_FILES" "$TEMP_INDEX_FILE" > /dev/null 2>&1

        if [ -f "$TEMP_INDEX_FILE" ]; then
            # 解析索引获取全量备份信息
            LATEST_FULL_BACKUP_ID=$(cat "$TEMP_INDEX_FILE" | jq -r '.backup_id')
            log_info "从MinIO找到最新全量备份: $LATEST_FULL_BACKUP_ID" "$step"

            # 清理临时文件
            rm -f "$TEMP_INDEX_FILE"
        else
            log_warn "无法下载备份索引文件" "$step"
        fi
    else
        log_warn "MinIO中没有找到全量备份索引文件" "$step"
    fi

    # 清理临时配置文件
    rm -f "$TEMP_S3CFG"
fi

# 获取并列出全量备份的PostgreSQL WAL-G备份名称
if [ -n "$LATEST_FULL_BACKUP" ]; then
    log_info "最新全量备份目录: $LATEST_FULL_BACKUP" "$step"

    # 从本地元数据文件中提取WAL-G备份名称
    if [ -f "$LATEST_FULL_BACKUP/metadata.json" ]; then
        PARENT_BACKUP=$(jq -r '.postgresql.walg_backup_name' "$LATEST_FULL_BACKUP/metadata.json")
        log_info "父备份名称: $PARENT_BACKUP" "$step"
    else
        log_warn "元数据文件不存在: $LATEST_FULL_BACKUP/metadata.json" "$step"
    fi
elif [ -n "$LATEST_FULL_BACKUP_ID" ]; then
    # 使用MinIO中找到的备份ID
    log_info "使用MinIO中的全量备份: $LATEST_FULL_BACKUP_ID" "$step"
    PARENT_BACKUP=""  # 这里我们不知道具体名称，但WAL-G会自动找到正确的父备份
else
    log_warn "无法找到全量备份，增量备份可能没有正确的父备份" "$step"
fi

# 获取增量备份的WAL-G备份名称
if [ "$USE_DOCKER" = "true" ]; then
    # 获取最新增量备份名称
    LATEST_BACKUP=$(docker exec -e WALG_S3_PREFIX="s3://${MINIO_BUCKET}/${MINIO_DIFF_PREFIX}" \
                                  -e AWS_ACCESS_KEY_ID="${MINIO_USER}" \
                                  -e AWS_SECRET_ACCESS_KEY="${MINIO_PASSWORD}" \
                                  -e AWS_ENDPOINT="http://${MINIO_HOST}:${MINIO_PORT}" \
                                  -e AWS_S3_FORCE_PATH_STYLE="true" \
                                  "$POSTGRES_CONTAINER_NAME" wal-g backup-list | tail -n 1 | awk '{print $1}')
else
    LATEST_BACKUP=$(WALG_S3_PREFIX="s3://${MINIO_BUCKET}/${MINIO_DIFF_PREFIX}" \
                   AWS_ACCESS_KEY_ID="${MINIO_USER}" \
                   AWS_SECRET_ACCESS_KEY="${MINIO_PASSWORD}" \
                   AWS_ENDPOINT="http://${MINIO_HOST}:${MINIO_PORT}" \
                   AWS_S3_FORCE_PATH_STYLE="true" \
                   $(which wal-g) backup-list | tail -n 1 | awk '{print $1}')
fi

if [ -z "$LATEST_BACKUP" ]; then
    log_warn "无法获取最新增量备份名称，使用备份ID作为标识" "$step"
    LATEST_BACKUP="$BACKUP_ID"
fi

log_success "PostgreSQL增量备份名称: $LATEST_BACKUP" "$step"

# 步骤4：备份ThingsBoard配置变更
step=$(next_step)
log_info "备份ThingsBoard配置变更..." "$step"

# 只备份自上次备份以来修改过的文件
if [ -d "$TB_CONFIG_DIR" ]; then
    # 创建配置变更目录
    mkdir -p "$BACKUP_DIR/thingsboard/config_changes"

    # 获取自上次全量备份以来修改过的文件
    if [ -n "$LATEST_FULL_BACKUP" ]; then
        FULL_BACKUP_TIME=$(stat -c %Y "$LATEST_FULL_BACKUP")

        # 查找比全量备份新的文件
        find "$TB_CONFIG_DIR" -type f -newer "$LATEST_FULL_BACKUP" -not -path "*/\.*" | while read -r file; do
            # 计算相对路径
            REL_PATH=$(realpath --relative-to="$TB_CONFIG_DIR" "$file")
            # 创建目标目录
            mkdir -p "$BACKUP_DIR/thingsboard/config_changes/$(dirname "$REL_PATH")"
            # 复制文件到备份目录
            cp "$file" "$BACKUP_DIR/thingsboard/config_changes/$REL_PATH"
        done

        # 如果找到了变更的文件，创建tar.gz归档
        if [ "$(find "$BACKUP_DIR/thingsboard/config_changes" -type f | wc -l)" -gt 0 ]; then
            tar -czf "$BACKUP_DIR/thingsboard/tb_config_changes.tar.gz" -C "$BACKUP_DIR/thingsboard/config_changes" .
            log_success "ThingsBoard配置变更备份完成" "$step"

            # 上传配置变更到MinIO
            upload_to_minio "$BACKUP_DIR/thingsboard/tb_config_changes.tar.gz" "$S3_PATH_PREFIX/thingsboard/tb_config_changes.tar.gz"
        else
            log_info "没有发现ThingsBoard配置文件变更" "$step"
        fi

        # 清理临时目录
        rm -rf "$BACKUP_DIR/thingsboard/config_changes"
    else
        log_warn "找不到全量备份时间点，将备份所有配置文件" "$step"
        tar -czf "$BACKUP_DIR/thingsboard/tb_config.tar.gz" -C "$(dirname "$TB_CONFIG_DIR")" "$(basename "$TB_CONFIG_DIR")"
        log_success "ThingsBoard所有配置文件备份完成" "$step"

        # 上传完整配置到MinIO
        upload_to_minio "$BACKUP_DIR/thingsboard/tb_config.tar.gz" "$S3_PATH_PREFIX/thingsboard/tb_config.tar.gz"
    fi
else
    log_warn "ThingsBoard配置目录不存在: $TB_CONFIG_DIR" "$step"
fi

# 步骤5：创建备份元数据文件
step=$(next_step)
log_info "创建备份元数据..." "$step"

cat > "$BACKUP_METADATA_FILE" <<EOF
{
  "backup_id": "$LATEST_BACKUP",
  "backup_type": "differential",
  "timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
  "postgresql": {
    "version": "$(docker exec $POSTGRES_CONTAINER_NAME psql -V | grep -oP "psql \(PostgreSQL\) \K[0-9\.]*")",
    "container": "$POSTGRES_CONTAINER_NAME",
    "walg_backup_name": "$LATEST_BACKUP",
    "parent_backup": "$PARENT_BACKUP",
    "database": "$THINGSBOARD_DATABASE_NAME"
  },
  "thingsboard": {
    "version": "3.3.4.1",
    "status": "$TB_STATUS",
    "config_dir": "$TB_CONFIG_DIR",
    "parent_full_backup": "${LATEST_FULL_BACKUP##*/}"
  },
  "system": {
    "hostname": "$(hostname)",
    "os": "$(cat /etc/os-release | grep PRETTY_NAME | cut -d= -f2 | tr -d '\"')",
    "architecture": "$(uname -m)",
    "kernel": "$(uname -r)"
  },
  "s3_storage": {
    "bucket": "${MINIO_BUCKET}",
    "prefix": "${S3_PATH_PREFIX}",
    "endpoint": "http://${MINIO_HOST}:${MINIO_PORT}",
    "postgresql_prefix": "${MINIO_DIFF_PREFIX}",
    "backup_files": [
      "${S3_PATH_PREFIX}/thingsboard/tb_config_changes.tar.gz",
      "${S3_PATH_PREFIX}/metadata.json"
    ],
    "parent_backup_id": "${LATEST_FULL_BACKUP_ID:-${LATEST_FULL_BACKUP##*/}}"
  }
}
EOF
log_success "备份元数据文件创建完成" "$step"

# 上传元数据文件到MinIO
upload_to_minio "$BACKUP_METADATA_FILE" "$S3_PATH_PREFIX/metadata.json"

# 创建备份索引文件到MinIO根目录
cat > "$BACKUP_DIR/backup_index.json" <<EOF
{
  "backup_id": "$LATEST_BACKUP",
  "backup_type": "differential",
  "timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
  "metadata_path": "$S3_PATH_PREFIX/metadata.json",
  "walg_backup_name": "$LATEST_BACKUP",
  "parent_backup_id": "${LATEST_FULL_BACKUP_ID:-${LATEST_FULL_BACKUP##*/}}"
}
EOF

# 上传备份索引到MinIO（用于快速查找备份）
upload_to_minio "$BACKUP_DIR/backup_index.json" "thingsboard-backup/index/${LATEST_BACKUP}.json"

# 步骤6：备份完成
step=$(next_step)
log_success "增量备份完成: $LATEST_BACKUP" "$step"
log_info "备份已上传到MinIO: s3://$MINIO_BUCKET/$S3_PATH_PREFIX/" "$step"

# 步骤7：清理本地临时文件
step=$(next_step)
log_info "清理本地临时文件..." "$step"
rm -rf "$BACKUP_DIR"
log_success "本地临时文件已清理" "$step"

# 步骤8：发送通知
step=$(next_step)
log_info "发送备份完成通知..." "$step"
if [ "$ENABLE_NOTIFICATIONS" = "true" ]; then
    send_notification "ThingsBoard增量备份完成" "备份ID: $LATEST_BACKUP\n备份地址: s3://$MINIO_BUCKET/$S3_PATH_PREFIX/"
    log_success "备份通知已发送" "$step"
else
    log_info "通知功能未启用，跳过发送" "$step"
fi

exit 0
